using System;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using NUnit.Framework;

namespace MefContrib.Models.Provider.Tests.Definitions
{
    public abstract class DefinitionProviderTests
    {
        protected abstract CompositionContainer Container { get; }

        [Test]
        public void ResolveSinglePartByContractTypeTest()
        {
            var lazyExport = Container.GetExport<IFoo>();
            Assert.That(lazyExport, Is.Not.Null);
            Assert.That(lazyExport.Value, Is.Not.Null);
            Assert.That(lazyExport.Value.GetType(), Is.EqualTo(typeof(Foo1)));
        }

        [Test]
        public void ResolveSinglePartByContractNameTest()
        {
            var lazyExport = Container.GetExport<IFoo>("Foo2");
            Assert.That(lazyExport, Is.Not.Null);
            Assert.That(lazyExport.Value, Is.Not.Null);
            Assert.That(lazyExport.Value.GetType(), Is.EqualTo(typeof(Foo2)));
        }

        [Test]
        public void ResolveCompositePartByContractTypeWithPropertyInjectionTest()
        {
            var lazyBar = Container.GetExport<Bar1>();
            Assert.That(lazyBar, Is.Not.Null);
            Assert.That(lazyBar.Value, Is.Not.Null);
            Assert.That(lazyBar.Value.Foo, Is.Not.Null);
            Assert.That(lazyBar.Value.Foo.GetType(), Is.EqualTo(typeof(Foo1)));
            Assert.That(lazyBar.Value.MefComponent, Is.Not.Null);
        }

        [Test]
        public void ResolveManyPartsByContractTypeTest()
        {
            var lazyExports = Container.GetExports<IMany>();
            Assert.That(lazyExports, Is.Not.Null);
            Assert.That(lazyExports.Count(), Is.EqualTo(2));
        }

        [Test]
        public void ResolvePartExportedByDefaultContractTypeTest()
        {
            var lazyExport = Container.GetExport<DefaultContractExport>();
            Assert.That(lazyExport, Is.Not.Null);
            Assert.That(lazyExport.Value, Is.Not.Null);
        }

        [Test]
        public void ResolvePartContainingImportUsingDefaultContractTypeTest()
        {
            var lazyExport = Container.GetExport<DefaultContractImport>();
            Assert.That(lazyExport, Is.Not.Null);
            Assert.That(lazyExport.Value, Is.Not.Null);
            Assert.That(lazyExport.Value.Foo, Is.Not.Null);
        }

        // TODO: constructor injection is not yet supported, test fails
        //[Test]
        public void ResolveCompositePartByContractTypeWithConstructorInjectionTest()
        {
            var lazyBar = Container.GetExport<Bar2>();
            Assert.That(lazyBar, Is.Not.Null);
            Assert.That(lazyBar.Value, Is.Not.Null);
            Assert.That(lazyBar.Value.Foo, Is.Not.Null);
            Assert.That(lazyBar.Value.Foo.GetType(), Is.EqualTo(typeof(Foo1)));
            Assert.That(lazyBar.Value.MefComponent, Is.Not.Null);
        }

        [Test]
        public void ResolvePropertyExportedByContractTypeTest()
        {
            var lazy = Container.GetExport<PropretImporterUsingDefaultContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value.Value, Is.EqualTo(223344));
        }

        [Test]
        public void ResolvePropertyExportedByContractNameTest()
        {
            var lazy = Container.GetExport<PropretImporterUsingNamedContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value.Value, Is.EqualTo(112233));
        }

        [Test]
        public void ResolveFieldExportedByContractTypeTest()
        {
            var lazy = Container.GetExport<FieldImporterUsingDefaultContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value._stringField2, Is.EqualTo("test string 2"));
        }

        [Test]
        public void ResolveFieldExportedByContractNameTest()
        {
            var lazy = Container.GetExport<FieldImporterUsingNamedContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value._stringField2, Is.EqualTo("test string"));
        }

        [Test]
        public void ResolveMethodExportedByContractTypeTest()
        {
            var lazy = Container.GetExport<MethodImporterUsingDefaultContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value.BarMethod(12, 10.0), Is.EqualTo("Result=22"));
        }

        [Test]
        public void ResolveMethodExportedByContractNameTest()
        {
            var lazy = Container.GetExport<MethodImporterUsingNamedContract>();
            Assert.That(lazy, Is.Not.Null);
            Assert.That(lazy.Value, Is.Not.Null);
            Assert.That(lazy.Value.BarMethod(12, 10.0), Is.EqualTo("Result=120"));
        }
    }
}